<!-- 图片裁剪弹窗 -->
<template>
    <el-dialog
        v-model="show"
        width="634px"
        top="28px"
        title="图片裁剪"
        append-to-body
        :close-on-click-modal="false"
        @opened="onOpen"
        @closed="onClose"
    >
        <div class="content">
            <div class="content-left">
                <div
                    v-loading="!cropper.ready"
                    element-loading-text="图片加载中..."
                    class="image-wrap"
                >
                    <img :id="imageId" class="image-ele">
                </div>
                <div class="bottom-action">
                    <el-radio-group v-model="aspectRatio" size="small">
                        <el-radio-button :label="1/1">1:1</el-radio-button>
                        <el-radio-button :label="3/4">3:4</el-radio-button>
                        <el-radio-button :label="4/3">4:3</el-radio-button>
                        <el-radio-button :label="16/9">16:9</el-radio-button>
                        <el-radio-button :label="0">自由</el-radio-button>
                    </el-radio-group>
                    <el-button type="primary" size="small" title="刷新" style="margin-left: 10px;" @click="onReset">
                        <el-icon><icon-refresh /></el-icon>
                    </el-button>
                </div>
            </div>
            <div class="content-right">
                <div :id="previewImageId" class="preview-image"></div>
                <div class="actions-warp">
                    <div class="row-item">
                        <div class="row-item-label">
                            宽度
                        </div>
                        <div class="row-item-content">
                            <el-input-number
                                v-model="cropperWidth"
                                :min="0"
                                size="small"
                                controls-position="right"
                            />
                        </div>
                    </div>
                    <div class="row-item">
                        <div class="row-item-label">
                            高度
                        </div>
                        <div class="row-item-content">
                            <el-input-number
                                v-model="cropperHeight"
                                :min="0"
                                size="small"
                                controls-position="right"
                            />
                        </div>
                    </div>
                    <div class="row-item">
                        <div class="row-item-label">
                            距左
                        </div>
                        <div class="row-item-content">
                            <el-input-number
                                v-model="cropperLeft"
                                :min="0"
                                size="small"
                                controls-position="right"
                            />
                        </div>
                    </div>
                    <div class="row-item">
                        <div class="row-item-label">
                            距上
                        </div>
                        <div class="row-item-content">
                            <el-input-number
                                v-model="cropperTop"
                                :min="0"
                                size="small"
                                controls-position="right"
                            />
                        </div>
                    </div>

                    <el-button-group size="small">
                        <el-button type="primary" title="左旋转" @click="onRotate(-90)"><el-icon><icon-refresh-left /></el-icon></el-button>
                        <el-button type="primary" title="右旋转" @click="onRotate(90)"><el-icon><icon-refresh-right /></el-icon></el-button>
                    </el-button-group>
                    <el-button-group size="small" style="margin-left: 10px;">
                        <el-button type="primary" title="左右反转" @click="onScale('X')"><el-icon><icon-repeat /></el-icon></el-button>
                        <el-button type="primary" title="上下反转" @click="onScale('Y')"><el-icon><icon-repeat-vertical /></el-icon></el-button>
                    </el-button-group>
                </div>
            </div>
        </div>

        <template #footer>
            <span class="dialog-footer">
                <el-button @click="onCancel">取消</el-button>
                <el-button type="primary" @click="onConfirmCropper">裁剪</el-button>
                <el-button type="primary" @click="onConfirm">确定</el-button>
            </span>
        </template>
    </el-dialog>
</template>

<script>
import { defineComponent, toRefs, ref, computed } from 'vue'
import { randomStr } from '@/libs/tools'
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.min.css'
export default defineComponent({
    name: 'ImageCropperDialog',
    props: {
        visible: {
            type: Boolean,
            default: false
        },
        url: {
            type: String,
            default: ''
        }
    },
    emits: [
        'update:visible',
        'crope',
        'confirm'
    ],
    setup(props, { emit }) {
        const { visible, url } = toRefs(props)
        const show = computed({
            get: () => visible.value,
            set: val => emit('update:visible', val)
        })

        const imageId = `cropper-${randomStr()}`
        const previewImageId = `cropper-preview-${randomStr()}`

        const cropper = ref({})
        const cropperW = ref(0)
        const cropperH = ref(0)
        const cropperL = ref(0)
        const cropperT = ref(0)

        const cropperWidth = computed({
            get: () => cropperW.value,
            set: val => cropper.value.setData({ width: val })
        })
        const cropperHeight = computed({
            get: () => cropperH.value,
            set: val => cropper.value.setData({ height: val })
        })
        const cropperLeft = computed({
            get: () => cropperL.value,
            set: val => cropper.value.setData({ x: val })
        })
        const cropperTop = computed({
            get: () => cropperT.value,
            set: val => cropper.value.setData({ y: val })
        })

        const onOpen = () => {
            const dom = document.getElementById(imageId)
            cropper.value = new Cropper(dom, {
                preview: `#${previewImageId}`,
                checkCrossOrigin: true,
                crop: e => {
                    const { width, height, x, y } = e.detail
                    cropperW.value = parseInt(width)
                    cropperH.value = parseInt(height)
                    cropperL.value = parseInt(x)
                    cropperT.value = parseInt(y)
                }
            })
            replace(url.value)
            aspectRatio.value = 0
        }
        const onClose = () => {
            destroy()
            cropperW.value = 0
            cropperH.value = 0
            cropperL.value = 0
            cropperT.value = 0
        }

        // 裁剪框的纵横比
        const aspectRatio = computed({
            get: () => cropper.value?.options?.aspectRatio || 0,
            set: val => setAspectRatio(val)
        })
        
        // 替换图片
        const replace = src => {
            cropper.value.replace(src)
        }
        // 销毁
        const destroy = () => {
            cropper.value.destroy()
        }

        // 重置
        const onReset = () => {
            replace(url.value)
            cropper.value.reset()
        }
        // 旋转图片
        const onRotate = (value = 90) => {
            cropper.value.rotate(value)
        }
        // 翻转图片
        const onScale = type => {
            cropper[`scale${type}`](-cropper.value.getData()[`scale${type}`])
        }
        // 更改裁剪框的纵横比
        const setAspectRatio = value => {
            cropper.value.setAspectRatio(value)
        }

        // 取消
        const onCancel = () => {
            show.value = false
        }
        // 确认裁剪
        const onConfirmCropper = () => {
            cropper.value.getCroppedCanvas().toBlob(blob => {
                emit('crope', blob)
            })
        }
        const onConfirm = () => {
            emit('confirm', url.value)
            show.value = false
        }

        return {
            show,
            url,

            imageId,
            previewImageId,
            cropper,
            cropperWidth,
            cropperHeight,
            cropperLeft,
            cropperTop,

            onOpen,
            onClose,

            aspectRatio,
            onReset,
            onRotate,
            onScale,

            onCancel,
            onConfirmCropper,
            onConfirm
        }
    }
})
</script>

<style lang="less" scoped>
@import './image-cropper-dialog.less';
</style>